import  {AxiosRequestConfig, AxiosInstance, AxiosResponse, AxiosError } from 'axios';
import {UploadFileParams, ContentTypeEnum, RequestEnum } from '../../../model/index';
import qs from 'qs';
import axios from 'axios';
// import { AxiosCanceler } from './axiosCancel';
// import { isFunction } from '../../is';
import { cloneDeep } from 'lodash-es';
class VAxios {
  private axiosInstance: AxiosInstance;
  private readonly options: AxiosRequestConfig;

  constructor(options: AxiosRequestConfig) {
    this.options = options;
    this.axiosInstance = axios.create(options);
    this.setupInterceptors();
  }


  private createAxios(config: AxiosRequestConfig): void {
    this.axiosInstance = axios.create(config);
  }

  getAxios(): AxiosInstance {
    return this.axiosInstance;
  }

  /**
   * @description: Reconfigure axios
   */
  configAxios(config: AxiosRequestConfig) {
    if (!this.axiosInstance) {
      return;
    }
    this.createAxios(config);
  }

  setHeader(headers: any): void {
    if (!this.axiosInstance) {
      return;
    }
    Object.assign(this.axiosInstance.defaults.headers, headers);
  }


  private setupInterceptors() {
 
    // const axiosCanceler = new AxiosCanceler()
    this.axiosInstance.interceptors.request.use((config) => {
      return config;
    }, (error:any) => {
      return Promise.reject(error);
  });

  // this.axiosInstance.interceptors.response.use(undefined, );
  }


  uploadFile<T = any>(config: AxiosRequestConfig, params: UploadFileParams) {
    const formData = new window.FormData();
    const customFilename = params.name || 'file';

    if (params.filename) {
      formData.append(customFilename, params.file, params.filename);
    } else {
      formData.append(customFilename, params.file);
    }

    if (params.data) {
      Object.keys(params.data).forEach((key) => {
        const value = params.data![key];
        if (Array.isArray(value)) {
          value.forEach((item) => {
            formData.append(`${key}[]`, item);
          });
          return;
        }

        formData.append(key, params.data![key]);
      });
    }

    return this.axiosInstance.request<T>({
      ...config,
      method: 'POST',
      data: formData,
      headers: {
        'Content-type': ContentTypeEnum.FORM_DATA,
        // @ts-ignore
        ignoreCancelToken: true,
      },
    });
  }

  // support form-data
  
  
  supportFormData(config: AxiosRequestConfig) {
    const headers = config.headers || this.options.headers;
    const contentType = headers?.['Content-Type'] || headers?.['content-type'];

    if (
      contentType !== ContentTypeEnum.FORM_URLENCODED ||
      !Reflect.has(config, 'data') ||
      config.method?.toUpperCase() === RequestEnum.GET
    ) {
      return config;
    }

    return {
      ...config,
      data: qs.stringify(config.data, { arrayFormat: 'brackets' }),
    };
  }

  get<T = any>(config: AxiosRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'GET' });
  }

  post<T = any>(config: AxiosRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'POST' });
  }

  put<T = any>(config: AxiosRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'PUT' });
  }

  delete<T = any>(config: AxiosRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'DELETE' });
  }

  request<T = any>(config: AxiosRequestConfig): Promise<T> {
    let conf: AxiosRequestConfig = cloneDeep(config);
    console.log(conf)
    conf = this.supportFormData(conf);
    return new Promise((resolve, reject) => {
      this.axiosInstance
        .request<any, AxiosResponse>(conf)
        .then((res: AxiosResponse) => {
          resolve(res as unknown as Promise<T>);
        })
        .catch((e: Error | AxiosError) => {
          // if (axios.isAxiosError(e)) {
          //   // rewrite error message from axios in here
          // }
          reject(e);
        });
    });
  }
}


const defHttp: VAxios = new VAxios({
  baseURL: import.meta.env.VITE_BASE_URL,
  headers: {
    "Content-Type": ContentTypeEnum.JSON 
  }

})
export default defHttp